import {Ik} from "./Ik.ts";
import {Planet} from "./Planet.ts";
import {player} from "./Player.ts";
import getMachineEnergy from "./MachineEnergy.ts";
import {globalConfig} from "./Data.ts";

export class Formula {
    // 输入材料
    input: Array<SourceItem> = []
    // 输出材料
    output: Array<ProductItem> = []
    // 一次工作时间
    time: number = 1
    // 进度 大于time时，记一次工作完成
    leftTime: number = 0
    // 机器名称
    machine: string = ''
    // 机器数量
    machineCount: number = 0

}

export class SourceItem {
    // 材料名称
    sim: string = ''
    // 材料数量
    sin: number = 1
    // 材料缓存数量 缓存上限为 pin * 10 * machineCount
    sic: number = 0

}

export class ProductItem {
    // 材料名称
    pim: string = ''
    // 材料数量
    pin: number = 1
    // 材料缓存数量 缓存上限为 pin * 10 * machineCount
    pic: number = 0

}

export let formulaLoop = () => {
    for (let star of globalConfig.map) {
        for (let planet of star.spl) {
            checkPlanet(planet)
        }
    }
}

let checkPlanet = (p: Planet) => {
    if (!p.pf) {
        return
    }
    for (let f of p.pf) {
        checkFormula(p, f)
    }
}

let checkFormula = (p: Planet, f: Formula) => {
    if (f.machineCount > 0) {
        // 检查缓存产物
        for (let i of f.output) {
            releaseToStore(p, i)
        }
        // 缓存原料
        for (let i of f.input) {
            cacheSource(p, f, i)
        }

        // 是否堵塞
        for (let i of f.output) {
            if (!checkProductCount(f, i)) {
                return
            }
        }

        // 是否原料不足
        for (let i of f.input) {
            if (!checkSourceCount(f, i)) {
                return
            }
        }

        // 是否电力不足
        if (!checkPower(p, f)) {
            return
        }

        // 是否进度完成
        let count = f.leftTime / f.time
        if (count > 0) {
            f.leftTime -= count * f.time
            for (let i of f.output) {
                i.pic += i.pin * count
            }
            for (let i of f.input) {
                i.sic -= i.sin * count
            }
        }
    }
}
// 检查电量
let checkPower = (p: Planet, f: Formula): boolean => {
    if (p.pe < f.machineCount * getMachineEnergy(f.machine)) {
        p.pet -= f.machineCount * getMachineEnergy(f.machine)
        return false
    }
    p.pe -= f.machineCount * getMachineEnergy(f.machine)
    p.pet -= f.machineCount * getMachineEnergy(f.machine)
    f.leftTime += f.machineCount
    return true
}

// 检查堵塞
let checkProductCount = (f: Formula, fi: ProductItem): boolean => {
    return fi.pic + fi.pin * f.machineCount <= fi.pin * 10 * f.machineCount
}

// 检查原料
let checkSourceCount = (f: Formula, fi: SourceItem): boolean => {
    return fi.sic >= fi.sin * f.machineCount
}

// 将机器产品缓存释放到星球仓储中
let releaseToStore = (p: Planet, fi: ProductItem): void => {
    if (fi.pic == 0) {
        return
    }
    if (!p.pim) {
        return
    }
    let item = p.pim.get(fi.pim)
    if (!item) {
        return
    }
    if (item.ic + fi.pic > item.im * player.itemPack) {
        fi.pic -= item.im * player.itemPack - item.ic
        item.ic = item.im * player.itemPack
    } else {
        item.ic += fi.pic
        fi.pic = 0
    }
}

let cacheSource = (p: Planet, f: Formula, fi: SourceItem): void => {
    if (fi.sic == fi.sin * 10 * f.machineCount) {
        return
    }
    let item = p.pim.get(fi.sim)
    if (!item) {
        return
    }
    if (item.ic + fi.sic > fi.sin * 10 * f.machineCount) {
        item.ic -= fi.sin * 10 * f.machineCount - fi.sic
        fi.sic = fi.sin * 10 * f.machineCount
    } else {
        fi.sic += item.ic
        item.ic = 0
    }
}

let formulaInfo: Array<Formula> = [
    Object.assign(new Formula(), {
        input: [
            Object.assign(new SourceItem(), {sim: Ik.铁矿})
        ],
        output: [
            Object.assign(new ProductItem(), {pim: Ik.铁块})
        ],
        time: 1,
        machine: "电弧熔炉"
    }),
    Object.assign(new Formula(), {
        input: [
            Object.assign(new SourceItem(), {sim: Ik.铁矿})
        ],
        output: [
            Object.assign(new ProductItem(), {pim: Ik.磁铁})
        ],
        time: 1.5,
        machine: "电弧熔炉"
    }),
    Object.assign(new Formula(), {
        input: [
            Object.assign(new SourceItem(), {sim: Ik.铜矿})
        ],
        output: [
            Object.assign(new ProductItem(), {pim: Ik.铜块})
        ],
        time: 1,
        machine: "电弧熔炉"
    }),
    Object.assign(new Formula(), {
        input: [
            Object.assign(new SourceItem(), {sim: Ik.铁块, sin: 2}),
            Object.assign(new SourceItem(), {sim: Ik.铜块})
        ],
        output: [
            Object.assign(new ProductItem(), {pim: Ik.电路板, sin: 2})
        ],
        time: 1,
        machine: "制造台MKI"
    }),
    Object.assign(new Formula(), {
        input: [
            Object.assign(new SourceItem(), {sim: Ik.铁块, sin: 2}),
            Object.assign(new SourceItem(), {sim: Ik.铜块})
        ],
        output: [
            Object.assign(new ProductItem(), {pim: Ik.电路板, pin: 2})
        ],
        time: 1,
        machine: "制造台MKI"
    }),
    Object.assign(new Formula(), {
        input: [
            Object.assign(new SourceItem(), {sim: Ik.磁铁, sin: 2}),
            Object.assign(new SourceItem(), {sim: Ik.铜块})
        ],
        output: [
            Object.assign(new ProductItem(), {pim: Ik.磁线圈, pin: 2})
        ],
        time: 1,
        machine: "制造台MKI"
    }),
    Object.assign(new Formula(), {
        input: [
            Object.assign(new SourceItem(), {sim: Ik.铁块})
        ],
        output: [
            Object.assign(new ProductItem(), {pim: Ik.齿轮})
        ],
        time: 1,
        machine: "制造台MKI"
    }),
    Object.assign(new Formula(), {
        input: [
            Object.assign(new SourceItem(), {sim: Ik.铁块, sin: 4}),
            Object.assign(new SourceItem(), {sim: Ik.电路板, sin: 2}),
            Object.assign(new SourceItem(), {sim: Ik.磁线圈, sin: 2}),
            Object.assign(new SourceItem(), {sim: Ik.齿轮, sin: 2})
        ],
        output: [
            Object.assign(new ProductItem(), {pim: Ik.齿轮})
        ],
        time: 1,
        machine: "制造台MKI"
    })
]

let allFormulaInfo = (): Array<Formula> => {
    let temp: Array<Formula> = []
    for (let f of formulaInfo) {
        temp.push(Object.assign(new Formula(), f))
    }
    return temp
}

export default allFormulaInfo